#include <iostream>
#include <string>

#include "multiindex.hpp"

using namespace MultiIndex;
using namespace std;

#define COMPARE(val1, val2) \
	if(val1 != val2) cout << "FAIL: " << __LINE__ << endl; \
	else cout << "PASS" << endl;

struct PairStruct1
{
	PairStruct1(int first, double second)
		: first(first)
		, second(second)
	{
	}

	int first;
	double second;
};

struct StringPair
{
	StringPair(const string& first, const string& second)
		: first(first)
		, second(second)
	{
	}
		string first;
		string second;
};

struct AnotherPair
{
	AnotherPair(const string& first, int second)
		: first(first)
		, second(second)
	{
	}
		string first;
		int second;
};


void testConstructor()
{
	typedef PairStruct1 MyPair;
	UniqueIndex< MultiIndexedContainer<MyPair>,
					FieldKeyExtractor<MyPair, int, &MyPair::first>> indexer;
	COMPARE(indexer.empty(), true);
	COMPARE(indexer.size(), 0);
}

void testInsert()
{
	typedef PairStruct1 MyPair;
	typedef UniqueIndex< MultiIndexedContainer<MyPair>,
					FieldKeyExtractor<MyPair, int, &MyPair::first>> SimpleIndexer;
	{
		SimpleIndexer indexer;
		SimpleIndexer::nth_iterator<0>::type it;

		COMPARE(indexer.insert(MyPair(1, 1.0)), true);
		COMPARE(indexer.insert(MyPair(0, 0.0)), true);
		COMPARE(indexer.insert(MyPair(2, 2.0)), true);

		it = indexer.begin<0>();
		COMPARE(it->first, 0);
		COMPARE(it->second, 0.0);

		++it;
		COMPARE(it->first, 1);
		COMPARE(it->second, 1.0);

		++it;
		COMPARE((*it).first, 2);
		COMPARE((*it).second, 2.0);

		COMPARE(indexer.empty(), false);
		COMPARE(indexer.size(), 3);

		COMPARE(indexer.insert(MyPair(2, 3.0)), false);
		COMPARE(indexer.empty(), false);
		COMPARE(indexer.size(), 3);

		it = indexer.end<0>();
		--it;
		COMPARE((*it).first, 2);
		COMPARE((*it).second, 2.0);
	}
}

void testIterateOver()
{
	typedef PairStruct1 MyPair;
	typedef UniqueIndex< MultiIndexedContainer<MyPair>,
						FieldKeyExtractor<MyPair, int, &MyPair::first>> SimpleIndexer;
	SimpleIndexer indexer;
	indexer.insert(MyPair(0, 0.0));
	indexer.insert(MyPair(1, 1.0));
	indexer.insert(MyPair(2, 2.0));

	SimpleIndexer::nth_iterator<0>::type it = indexer.begin<0>();
	unsigned int i = 0;

	while(it != indexer.end<0>())
	{
		i++;
		++it;
	}

	COMPARE(i, 3);
}

void testErase()
{
	typedef PairStruct1 MyPair;
	typedef UniqueIndex< MultiIndexedContainer<MyPair>,
		FieldKeyExtractor<MyPair, int, &MyPair::first>> SimpleIndexer;

	//erase by iterator
	{
		SimpleIndexer indexer;
		indexer.insert(MyPair(0, 0.0));
		indexer.insert(MyPair(1, 1.0));
		indexer.insert(MyPair(2, 2.0));

		indexer.erase(indexer.begin<0>());
		COMPARE(indexer.size(), 2);

		indexer.erase(indexer.begin<0>());
		COMPARE(indexer.size(), 1);

		indexer.erase(indexer.begin<0>());
		COMPARE(indexer.size(), 0);
	}

	//erase by key
	{
		SimpleIndexer indexer;
		indexer.insert(MyPair(0, 0.0));
		indexer.insert(MyPair(1, 1.0));
		indexer.insert(MyPair(2, 2.0));

		indexer.erase<0>(0);
		COMPARE(indexer.size(), 2);

		indexer.erase<0>(2);
		COMPARE(indexer.size(), 1);

		COMPARE(indexer.begin<0>()->first, 1);
		COMPARE(indexer.begin<0>()->second, 1.0);

		indexer.erase<0>(3);
		COMPARE(indexer.size(), 1);
	}
}

void testFind()
{
	typedef PairStruct1 MyPair;
	typedef UniqueIndex< MultiIndexedContainer<MyPair>,
		FieldKeyExtractor<MyPair, int, &MyPair::first>> SimpleIndexer;

	SimpleIndexer indexer;
	indexer.insert(MyPair(0, 0.0));
	indexer.insert(MyPair(1, 1.0));
	indexer.insert(MyPair(2, 2.0));

	{
		SimpleIndexer::nth_iterator<0>::type it = indexer.find<0>(1);
		COMPARE(it->first, 1);
		COMPARE(it->second, 1.0);
	}

	{
		SimpleIndexer::nth_iterator<0>::type it = indexer.find<0>(2);
		COMPARE(it->first, 2);
		COMPARE(it->second, 2.0);
	}

	{
		SimpleIndexer::nth_iterator<0>::type it = indexer.find<0>(0);
		COMPARE(it->first, 0);
		COMPARE(it->second, 0.0);
	}

	{
		SimpleIndexer::nth_iterator<0>::type it = indexer.find<0>(5);
		COMPARE(it, indexer.end<0>());
	}
}

void testCompositeConstructor()
{
	typedef PairStruct1 MyPair;
	typedef UniqueIndex< UniqueIndex< MultiIndexedContainer<MyPair>,
		FieldKeyExtractor<MyPair, int, &MyPair::first> >,
		FieldKeyExtractor<MyPair, double, &MyPair::second> > CompositeIndexer;

	CompositeIndexer indexer;
	COMPARE(indexer.empty(), true);
	COMPARE(indexer.size(), 0);
}

void testCompositeInsert()
{
	typedef PairStruct1 MyPair;
	typedef UniqueIndex< UniqueIndex< MultiIndexedContainer<MyPair>,
		FieldKeyExtractor<MyPair, int, &MyPair::first> >,
		FieldKeyExtractor<MyPair, double, &MyPair::second> > CompositeIndexer;

	{
		CompositeIndexer indexer;
		CompositeIndexer::nth_iterator<0>::type it;
		CompositeIndexer::nth_iterator<1>::type it2;

		COMPARE(indexer.insert(MyPair(1, 1.0)), true);
		COMPARE(indexer.insert(MyPair(0, 0.0)), true);
		COMPARE(indexer.insert(MyPair(2, 2.0)), true);

		it = indexer.begin<0>();
		COMPARE(it->first, 0);
		COMPARE(it->second, 0.0);

		++it;
		COMPARE(it->first, 1);
		COMPARE(it->second, 1.0);

		++it;
		COMPARE((*it).first, 2);
		COMPARE((*it).second, 2.0);

		COMPARE(indexer.empty(), false);
		COMPARE(indexer.size(), 3);

		COMPARE(indexer.insert(MyPair(2, 3.0)), false);
		COMPARE(indexer.empty(), false);
		COMPARE(indexer.size(), 3);

		COMPARE(indexer.insert(MyPair(3, 2.0)), false);
		COMPARE(indexer.empty(), false);
		COMPARE(indexer.size(), 3);

		it = indexer.end<0>();
		--it;
		COMPARE((*it).first, 2);
		COMPARE((*it).second, 2.0);

		{
			it2 = indexer.begin<1>();
			COMPARE(it2->first, 0);
			COMPARE(it2->second, 0.0);

			++it2;
			COMPARE(it2->first, 1);
			COMPARE(it2->second, 1.0);

			++it2;
			COMPARE((*it2).first, 2);
			COMPARE((*it2).second, 2.0);
		}
	}
}

void testCompositeErase()
{
	typedef PairStruct1 MyPair;
	typedef UniqueIndex< UniqueIndex< MultiIndexedContainer<MyPair>,
		FieldKeyExtractor<MyPair, int, &MyPair::first> >,
		FieldKeyExtractor<MyPair, double, &MyPair::second> > CompositeIndexer;

	//erase by iterator
	{
		CompositeIndexer indexer;
		indexer.insert(MyPair(0, 0.0));
		indexer.insert(MyPair(1, 1.0));
		indexer.insert(MyPair(2, 2.0));

		indexer.erase(indexer.begin<0>());
		COMPARE(indexer.size(), 2);

		indexer.erase(indexer.begin<0>());
		COMPARE(indexer.size(), 1);

		indexer.erase(indexer.begin<0>());
		COMPARE(indexer.size(), 0);
	}

	{
		CompositeIndexer indexer;
		indexer.insert(MyPair(0, 0.0));
		indexer.insert(MyPair(1, 1.0));
		indexer.insert(MyPair(2, 2.0));

		indexer.erase(indexer.begin<1>());
		COMPARE(indexer.size(), 2);

		indexer.erase(indexer.begin<1>());
		COMPARE(indexer.size(), 1);

		indexer.erase(indexer.begin<1>());
		COMPARE(indexer.size(), 0);
	}

	//erase by key
	{
		CompositeIndexer indexer;
		indexer.insert(MyPair(0, 0.0));
		indexer.insert(MyPair(1, 1.0));
		indexer.insert(MyPair(2, 2.0));

		indexer.erase<0>(0);
		COMPARE(indexer.size(), 2);

		indexer.erase<0>(2);
		COMPARE(indexer.size(), 1);

		COMPARE(indexer.begin<0>()->first, 1);
		COMPARE(indexer.begin<0>()->second, 1.0);

		indexer.erase<0>(3);
		COMPARE(indexer.size(), 1);
	}

	{
		CompositeIndexer indexer;
		indexer.insert(MyPair(0, 0.0));
		indexer.insert(MyPair(1, 1.0));
		indexer.insert(MyPair(2, 2.0));

		indexer.erase<1>(0.0);
		COMPARE(indexer.size(), 2);

		indexer.erase<1>(2.0);
		COMPARE(indexer.size(), 1);

		COMPARE(indexer.begin<1>()->first, 1);
		COMPARE(indexer.begin<1>()->second, 1.0);

		indexer.erase<1>(3.0);
		COMPARE(indexer.size(), 1);
	}
}

void testCompositeIterate()
{
	struct ThirdIndex {};

	typedef StringPair MyPair;
	
	typedef UniqueIndex< UniqueIndex< UniqueIndex< MultiIndexedContainer<MyPair>,
		FieldKeyExtractor<MyPair, string, &MyPair::first> >,
		FieldKeyExtractor<MyPair, string, &MyPair::second> >,
		FieldKeyExtractor<MyPair, string, &MyPair::second>, ThirdIndex, std::greater<string> > CompositeIndexer;

	CompositeIndexer indexer;

	indexer.insert(MyPair("Bjarne", "Stroustrup"));
	indexer.insert(MyPair("Andrei", "Alexandrescu"));
	indexer.insert(MyPair("Herb", "Sutter"));
	indexer.insert(MyPair("Scott", "Meyers"));

	CompositeIndexer::nth_iterator<0>::type it = indexer.begin<0>();
	{
		COMPARE(it->first, string("Andrei"));
		COMPARE(it->second, string("Alexandrescu"));
		++it;
	}

	{
		COMPARE(it->first, string("Bjarne"));
		COMPARE(it->second, string("Stroustrup"));
		++it;
	}

	{
		COMPARE(it->first, string("Herb"));
		COMPARE(it->second, string("Sutter"));
		++it;
	}

	{
		COMPARE(it->first, string("Scott"));
		COMPARE(it->second, string("Meyers"));
		++it;
	}

	CompositeIndexer::nth_iterator<1>::type it2 = indexer.begin<1>();
	{
		COMPARE(it2->first, string("Andrei"));
		COMPARE(it2->second, string("Alexandrescu"));
		++it2;
	}

	{
		COMPARE(it2->first, string("Scott"));
		COMPARE(it2->second, string("Meyers"));
		++it2;
	}

	{
		COMPARE(it2->first, string("Bjarne"));
		COMPARE(it2->second, string("Stroustrup"));
		++it2;
	}

	{
		COMPARE(it2->first, string("Herb"));
		COMPARE(it2->second, string("Sutter"));
		++it2;
	}

	CompositeIndexer::tagged_iterator<ThirdIndex>::type it3 = indexer.begin<ThirdIndex>();

	{
		COMPARE(it3->first, string("Herb"));
		COMPARE(it3->second, string("Sutter"));
		++it3;
	}

	{
		COMPARE(it3->first, string("Bjarne"));
		COMPARE(it3->second, string("Stroustrup"));
		++it3;
	}

	{
		COMPARE(it3->first, string("Scott"));
		COMPARE(it3->second, string("Meyers"));
		++it3;
	}

	{
		COMPARE(it3->first, string("Andrei"));
		COMPARE(it3->second, string("Alexandrescu"));
		++it3;
	}

}

void testNonUniqueEqualRange()
{
	typedef StringPair MyPair;

	typedef UniqueIndex< NonUniqueIndex< MultiIndexedContainer<MyPair>,
		FieldKeyExtractor<MyPair, string, &MyPair::first> >,
		FieldKeyExtractor<MyPair, string, &MyPair::second> > CompositeIndexer;

	typedef CompositeIndexer::nth_iterator<0>::type FirstFieldIterator;


	CompositeIndexer indexer;

	indexer.insert(MyPair("string1", "asdasd"));
	indexer.insert(MyPair("string1", "sdfsdfsdf"));
	indexer.insert(MyPair("string1", "sdfssdfdfsdf"));
	indexer.insert(MyPair("uuu", "Meyers"));
	indexer.insert(MyPair("uuu", "Meyssdfsdfers"));

	const std::pair<FirstFieldIterator, FirstFieldIterator>& range = indexer.equal_range<0>("string1");

	FirstFieldIterator begin = indexer.begin<0>();
	COMPARE(range.first, begin);
	COMPARE(range.second, --(--indexer.end<0>()));

	const std::pair<FirstFieldIterator, FirstFieldIterator>& range2 = indexer.equal_range<0>("uuu");

	COMPARE(range2.first, range.second);
	COMPARE(range2.second, indexer.end<0>());
}

void testNonUniqueErase()
{
	
	{
		typedef StringPair MyPair;
		typedef UniqueIndex< NonUniqueIndex< MultiIndexedContainer<MyPair>,
			FieldKeyExtractor<MyPair, string, &MyPair::first> >,
			FieldKeyExtractor<MyPair, string, &MyPair::second> > CompositeIndexer;

		typedef CompositeIndexer::nth_iterator<0>::type FirstFieldIterator;

		CompositeIndexer indexer;

		indexer.insert(MyPair("string1", "asdasd"));
		indexer.insert(MyPair("string1", "sdfsdfsdf"));
		indexer.insert(MyPair("string1", "sdfssdfdfsdf"));
		indexer.insert(MyPair("uuu", "Meyers"));
		indexer.insert(MyPair("uuu", "Meyssdfsdfers"));


		COMPARE(indexer.size(), 5);

		indexer.erase<0>("string1");
		COMPARE(indexer.size(), 2);

		indexer.erase<0>("uuu");
		COMPARE(indexer.size(), 0);
	}
	
	{
		typedef StringPair MyPair;
		typedef NonUniqueIndex< UniqueIndex< MultiIndexedContainer<MyPair>,
			FieldKeyExtractor<MyPair, string, &MyPair::first> >,
			FieldKeyExtractor<MyPair, string, &MyPair::second> > CompositeIndexer;

		typedef CompositeIndexer::nth_iterator<0>::type FirstFieldIterator;

		CompositeIndexer indexer;

		indexer.insert(MyPair("string1", "asdasd"));

		COMPARE(indexer.size(), 1);

		indexer.erase<1>("asdasd");
		COMPARE(indexer.size(), 0);
	}

	{
		typedef StringPair MyPair;
		typedef UniqueIndex< UniqueIndex< MultiIndexedContainer<MyPair>,
			FieldKeyExtractor<MyPair, string, &MyPair::first> >,
			FieldKeyExtractor<MyPair, string, &MyPair::second> > CompositeIndexer;

		struct MyPair2
		{
			MyPair2(const MyPair* first, const string& second)
				: first(first)
				, second(second)
			{
			}
			const MyPair* first;
			string second;
		};

		typedef UniqueIndex< UniqueIndex< MultiIndexedContainer<MyPair2>,
			KeyFromKeyExtractor<
				FieldKeyExtractor<MyPair, string, &MyPair::first>,
				FieldKeyExtractor<MyPair2, const MyPair*, &MyPair2::first> >>,
			FieldKeyExtractor<MyPair2, string, &MyPair2::second> > CompositeIndexer2;

		CompositeIndexer indexer;
		CompositeIndexer2 indexer2;

		indexer.insert(MyPair(string("MyPair11"), string("MyPair12")));
		const MyPair* pair = &*indexer.find<0>(string("MyPair11"));

		indexer2.insert(MyPair2(pair, string("MyPair22")));

		
		indexer2.erase<0>(string("MyPair11"));
		COMPARE(indexer2.size(), 0);
	}
}

void testIdentityKeyExtractor()
{
	typedef UniqueIndex<MultiIndexedContainer<string>,
				IdentityKeyExtractor<string> > Indexer;

	Indexer indexer;
	
	indexer.insert("a");
	indexer.insert("b");
	indexer.insert("c");
	indexer.insert("d");
	indexer.insert("z");

	COMPARE(indexer.size(), 5);
	COMPARE(*indexer.begin<0>(), "a");
	COMPARE(*(--indexer.end<0>()), "z");
}


void testIndexTagging()
{
	{
		typedef AnotherPair MyPair;
		typedef UniqueIndex< UniqueIndex< MultiIndexedContainer<MyPair>,
			FieldKeyExtractor<MyPair, string, &MyPair::first>>,
			FieldKeyExtractor<MyPair, int, &MyPair::second>> CompositeIndexer;

		struct MyPair2
		{
			MyPair2(const MyPair* first, double second)
				: first(first)
				, second(second)
			{
			}
			const MyPair* first;
			double second;
		};

		typedef UniqueIndex< UniqueIndex< MultiIndexedContainer<MyPair2>,
			KeyFromKeyExtractor<
				FieldKeyExtractor<MyPair, string, &MyPair::first>,
				FieldKeyExtractor<MyPair2, const MyPair*, &MyPair2::first> >>,
			FieldKeyExtractor<MyPair2, double, &MyPair2::second>> CompositeIndexer2;

		CompositeIndexer indexer;
		CompositeIndexer2 indexer2;

		indexer.insert(MyPair(string("MyPair11"), 42));

		const MyPair* pair = &(*indexer.find<string>(string("MyPair11")));

		indexer2.insert(MyPair2(pair, 42.0));


		indexer2.erase<string>(string("MyPair11"));
		COMPARE(indexer2.size(), 0);
	}

	{
		struct MyPair
		{
			MyPair(const int* const first, double second)
				: first(first)
				, second(second)
			{
			}

			const int* const first;
			double second;
		};

		typedef NonUniqueIndex< UniqueIndex< MultiIndexedContainer<MyPair>,
			FieldKeyExtractor<MyPair, const int* const, &MyPair::first>>,
			FieldKeyExtractor<MyPair, double, &MyPair::second>> CompositeIndexer; //remove pointer and consts

		CompositeIndexer indexer;

		CompositeIndexer::tagged_iterator<int>::type it;
		CompositeIndexer::tagged_iterator<double>::type it2;

		int int_arr[4] = {0, 1, 2, 3};

		COMPARE(indexer.insert(MyPair(&int_arr[1], 1.0)), true);
		COMPARE(indexer.insert(MyPair(&int_arr[0], 0.0)), true);
		COMPARE(indexer.insert(MyPair(&int_arr[2], 2.0)), true);

		it = indexer.begin<int>();
		COMPARE(it->first, &int_arr[0]);
		COMPARE(it->second, 0.0);

		++it;
		COMPARE(it->first, &int_arr[1]);
		COMPARE(it->second, 1.0);

		++it;
		COMPARE((*it).first, &int_arr[2]);
		COMPARE((*it).second, 2.0);

		COMPARE(indexer.empty(), false);
		COMPARE(indexer.size(), 3);

		COMPARE(indexer.insert(MyPair(&int_arr[2], 3.0)), false);
		COMPARE(indexer.empty(), false);
		COMPARE(indexer.size(), 3);

		COMPARE(indexer.insert(MyPair(&int_arr[3], 2.0)), true);
		COMPARE(indexer.empty(), false);
		COMPARE(indexer.size(), 4);

		it = indexer.end<int>();
		--it;
		COMPARE((*it).first, &int_arr[3]);
		COMPARE((*it).second, 2.0);

		{
			it2 = indexer.begin<double>();
			COMPARE(it2->first, &int_arr[0]);
			COMPARE(it2->second, 0.0);

			++it2;
			COMPARE(it2->first, &int_arr[1]);
			COMPARE(it2->second, 1.0);

			++it2;
			COMPARE((*it2).first, &int_arr[2]);
			COMPARE((*it2).second, 2.0);

			++it2;
			COMPARE((*it2).first, &int_arr[3]);
			COMPARE((*it2).second, 2.0);
		}
	}

	{
		typedef PairStruct1 MyPair;
		typedef NonUniqueIndex< UniqueIndex< MultiIndexedContainer<MyPair>,
			FieldKeyExtractor<MyPair, int, &MyPair::first>>,
			FieldKeyExtractor<MyPair, double, &MyPair::second>> CompositeIndexer;

		CompositeIndexer indexer;
		CompositeIndexer::tagged_iterator<int>::type it;
		CompositeIndexer::tagged_iterator<double>::type it2;

		COMPARE(indexer.insert(MyPair(1, 1.0)), true);
		COMPARE(indexer.insert(MyPair(0, 0.0)), true);
		COMPARE(indexer.insert(MyPair(2, 2.0)), true);

		it = indexer.begin<int>();
		COMPARE(it->first, 0);
		COMPARE(it->second, 0.0);

		++it;
		COMPARE(it->first, 1);
		COMPARE(it->second, 1.0);

		++it;
		COMPARE((*it).first, 2);
		COMPARE((*it).second, 2.0);

		COMPARE(indexer.empty(), false);
		COMPARE(indexer.size(), 3);

		COMPARE(indexer.insert(MyPair(2, 3.0)), false);
		COMPARE(indexer.empty(), false);
		COMPARE(indexer.size(), 3);

		COMPARE(indexer.insert(MyPair(3, 2.0)), true);
		COMPARE(indexer.empty(), false);
		COMPARE(indexer.size(), 4);

		it = indexer.end<int>();
		--it;
		COMPARE((*it).first, 3);
		COMPARE((*it).second, 2.0);

		{
			it2 = indexer.begin<double>();
			COMPARE(it2->first, 0);
			COMPARE(it2->second, 0.0);

			++it2;
			COMPARE(it2->first, 1);
			COMPARE(it2->second, 1.0);

			++it2;
			COMPARE((*it2).first, 2);
			COMPARE((*it2).second, 2.0);

			++it2;
			COMPARE((*it2).first, 3);
			COMPARE((*it2).second, 2.0);
		}
	}
}

void testIndexCustomTagging()
{
	{
		struct FirstIndex {};
		struct SecondIndex {};

		typedef StringPair MyPair;
		typedef UniqueIndex< NonUniqueIndex< MultiIndexedContainer<MyPair>,
			FieldKeyExtractor<MyPair, string, &MyPair::first>, FirstIndex >,
			FieldKeyExtractor<MyPair, string, &MyPair::second>, SecondIndex > CompositeIndexer;

		typedef CompositeIndexer::nth_iterator<0>::type FirstFieldIterator;
		typedef CompositeIndexer::tagged_iterator<FirstIndex>::type FirstIndexIterator;

		CompositeIndexer indexer;

		indexer.insert(MyPair("string1", "asdasd"));
		indexer.insert(MyPair("string1", "sdfsdfsdf"));
		indexer.insert(MyPair("string1", "sdfssdfdfsdf"));
		indexer.insert(MyPair("uuu", "Meyers"));
		indexer.insert(MyPair("uuu", "Meyssdfsdfers"));


		COMPARE(indexer.size(), 5);

		indexer.erase<FirstIndex>("string1");
		COMPARE(indexer.size(), 2);

		indexer.erase<FirstIndex>("uuu");
		COMPARE(indexer.size(), 0);
	}

	{
		struct FirstIndex {};
		struct SecondIndex {};

		typedef PairStruct1 MyPair;
		typedef NonUniqueIndex< UniqueIndex< MultiIndexedContainer<MyPair>,
			FieldKeyExtractor<MyPair, int, &MyPair::first>, FirstIndex >,
			FieldKeyExtractor<MyPair, double, &MyPair::second>, SecondIndex > CompositeIndexer;

		CompositeIndexer indexer;
		CompositeIndexer::tagged_iterator<FirstIndex>::type it;
		CompositeIndexer::tagged_iterator<SecondIndex>::type it2;

		COMPARE(indexer.insert(MyPair(1, 1.0)), true);
		COMPARE(indexer.insert(MyPair(0, 0.0)), true);
		COMPARE(indexer.insert(MyPair(2, 2.0)), true);

		it = indexer.begin<FirstIndex>();
		COMPARE(it->first, 0);
		COMPARE(it->second, 0.0);

		++it;
		COMPARE(it->first, 1);
		COMPARE(it->second, 1.0);

		++it;
		COMPARE((*it).first, 2);
		COMPARE((*it).second, 2.0);

		COMPARE(indexer.empty(), false);
		COMPARE(indexer.size(), 3);

		COMPARE(indexer.insert(MyPair(2, 3.0)), false);
		COMPARE(indexer.empty(), false);
		COMPARE(indexer.size(), 3);

		COMPARE(indexer.insert(MyPair(3, 2.0)), true);
		COMPARE(indexer.empty(), false);
		COMPARE(indexer.size(), 4);

		it = indexer.end<FirstIndex>();
		--it;
		COMPARE((*it).first, 3);
		COMPARE((*it).second, 2.0);

		{
			it2 = indexer.begin<SecondIndex>();
			COMPARE(it2->first, 0);
			COMPARE(it2->second, 0.0);

			++it2;
			COMPARE(it2->first, 1);
			COMPARE(it2->second, 1.0);

			++it2;
			COMPARE((*it2).first, 2);
			COMPARE((*it2).second, 2.0);

			++it2;
			COMPARE((*it2).first, 3);
			COMPARE((*it2).second, 2.0);
		}
	}

	{
		struct FirstIndex {};
		struct SecondIndex {};

		typedef StringPair MyPair;
		typedef UniqueIndex< NonUniqueIndex< MultiIndexedContainer<MyPair>,
			FieldKeyExtractor<MyPair, string, &MyPair::first>, FirstIndex >,
			FieldKeyExtractor<MyPair, string, &MyPair::second>, SecondIndex > CompositeIndexer;

		typedef CompositeIndexer::tagged_iterator<FirstIndex>::type FirstFieldIterator;


		CompositeIndexer indexer;

		indexer.insert(MyPair("string1", "asdasd"));
		indexer.insert(MyPair("string1", "sdfsdfsdf"));
		indexer.insert(MyPair("string1", "sdfssdfdfsdf"));
		indexer.insert(MyPair("uuu", "Meyers"));
		indexer.insert(MyPair("uuu", "Meyssdfsdfers"));

		const std::pair<FirstFieldIterator, FirstFieldIterator>& range = indexer.equal_range<FirstIndex>("string1");

		FirstFieldIterator begin = indexer.begin<0>();
		COMPARE(range.first, begin);
		COMPARE(range.second, --(--indexer.end<0>()));

		const std::pair<FirstFieldIterator, FirstFieldIterator>& range2 = indexer.equal_range<FirstIndex>("uuu");

		COMPARE(range2.first, range.second);
		COMPARE(range2.second, indexer.end<0>());
	}

	{
		struct FirstIndex {};
		struct SecondIndex {};

		typedef StringPair MyPair;
		typedef NonUniqueIndex< UniqueIndex< MultiIndexedContainer<MyPair>,
			FieldKeyExtractor<MyPair, string, &MyPair::first>, FirstIndex >,
			FieldKeyExtractor<MyPair, string, &MyPair::second>, SecondIndex > CompositeIndexer;

		typedef CompositeIndexer::tagged_iterator<FirstIndex>::type FirstFieldIterator;

		CompositeIndexer indexer;

		indexer.insert(MyPair("string1", "asdasd"));

		COMPARE(indexer.size(), 1);

		indexer.erase<SecondIndex>("asdasd");
		COMPARE(indexer.size(), 0);
	}

	{
		struct FirstIndex {};
		struct SecondIndex {};

		typedef StringPair MyPair;
		typedef UniqueIndex< UniqueIndex< MultiIndexedContainer<MyPair>,
			FieldKeyExtractor<MyPair, string, &MyPair::first>, FirstIndex >,
			FieldKeyExtractor<MyPair, string, &MyPair::second>, SecondIndex > CompositeIndexer;

		struct MyPair2
		{
			MyPair2(const MyPair* first, const string& second)
				: first(first)
				, second(second)
			{
			}
			const MyPair* first;
			string second;
		};

		typedef UniqueIndex< UniqueIndex< MultiIndexedContainer<MyPair2>,
			KeyFromKeyExtractor<
				FieldKeyExtractor<MyPair, string, &MyPair::first>,
				FieldKeyExtractor<MyPair2, const MyPair*, &MyPair2::first> >, FirstIndex >,
			FieldKeyExtractor<MyPair2, string, &MyPair2::second>, SecondIndex > CompositeIndexer2;

		CompositeIndexer indexer;
		CompositeIndexer2 indexer2;

		indexer.insert(MyPair(string("MyPair11"), string("MyPair12")));

		const MyPair* pair = &(*indexer.find<FirstIndex>(string("MyPair11")));

		indexer2.insert(MyPair2(pair, string("MyPair22")));


		indexer2.erase<FirstIndex>(string("MyPair11"));
		COMPARE(indexer2.size(), 0);
	}
}

int main(int argc, char* argv[])
{
	testConstructor();
	testCompositeConstructor();
	testInsert();
	testCompositeInsert();
	testIterateOver();
	testCompositeIterate();
	testErase();
	testCompositeErase();
	testFind();
	testIdentityKeyExtractor();
	testIndexTagging();
	testIndexCustomTagging();
	testNonUniqueEqualRange();
	testNonUniqueErase();
	return 0;
}